//
// Created by yunnan xu on 2021/6/12.
//

#include "RenderItemOpaque.h"
#include "RenderItem.h"
#include "Buffer.h"
#include "GLESUtils.h"
#include "Model.h"
#include "DummyModel.h"
#include "MeshModel.h"
#include "SkinnedMeshModel.h"
#include "Texture.h"
#include "Scene.h"
#include "Camera.h"
#include <gles3/gl32.h>
#include <ext.hpp>


RenderItemOpaque<GraphicsAPI::GLESv3>::RenderItemOpaque() : IRenderItem()
{
    GL_CHECK(glGenVertexArrays(1, &vertexArrayObject));
}


void RenderItemOpaque<GraphicsAPI::GLESv3>::AppendVertexAttribData(VertexAttribType attrib_type, const void * data,  uint size, uint stride, uint offset)
{
    GL_CHECK(glBindVertexArray(vertexArrayObject));

    /*
     * GLESBuffer 构造函数参数
     * GLenum buffer_target, GLenum usage, long offset, long size, const void * data
     * */

    GL_CHECK(vertexAttribBufferList.emplace_back(
            std::make_pair(
                    attrib_type,
                    std::make_shared<VertexBuffer<GraphicsAPI::GLESv3>>(GL_ARRAY_BUFFER, GL_STATIC_DRAW, offset, size, data)
            )
    ));

    int index = (int) vertexAttribBufferList.size() - 1;

    GL_CHECK(glVertexAttribPointer(
            index,
            GLESVertexAttribToCount[(int) attrib_type],
            GLESVertexAttribToEnum[(int) attrib_type],
            GL_FALSE,
            stride,
            reinterpret_cast<GLvoid*>(offset)
    ));

    GL_CHECK(glEnableVertexAttribArray(index));

    GL_CHECK(glBindVertexArray(0));

    TryGetGLError("GLESRenderItem::AppendVertexAttribData");
}

void RenderItemOpaque<GraphicsAPI::GLESv3>::SetElementData(const void * element_data, size_t element_data_length)
{
    GL_CHECK(glBindVertexArray(vertexArrayObject));
    /*
     * 函数原型
     * GLESBuffer(GLenum buffer_target, GLenum usage, long offset, long size, const void * data);
     * */
    vertexIndexBuffer = GL_CHECK(std::make_shared<VertexBuffer<GraphicsAPI::GLESv3>>(GL_ELEMENT_ARRAY_BUFFER, GL_STATIC_DRAW, 0, element_data_length, (const void *) element_data));
    GL_CHECK(glBindVertexArray(0));
    TryGetGLError("GLESRenderItem::SetElementData");
}

void RenderItemOpaque<GraphicsAPI::GLESv3>::LoadDummyData(DummyItemType dummy_type, glm::vec3 translation, glm::vec3 rotation, glm::vec3 scale, bool with_rb)
{

    /*
     * AppendVertexAttribData 函数原型
     *  void AppendVertexAttribData(VertexAttribType attrib_type, const void * data, uint count, uint strip, uint offset);
     * */
    auto attrib_type_list = std::unordered_set<VertexAttribType> {
            VertexAttribType::POSITION_F3,
            VertexAttribType::NORMAL_F3,
            VertexAttribType::UV1_F2
    };

    switch(dummy_type) {
        case DummyItemType::Plane:
            model = GL_CHECK(DummyModel::MakeDummyModel<DummyItemType::Plane>(attrib_type_list, with_rb, 10.0f, 10.0f));
            break;

        case DummyItemType::Triangle:
            break;

        case DummyItemType::Box:
            model = GL_CHECK(DummyModel::MakeDummyModel<DummyItemType::Box>(attrib_type_list, with_rb, 1.0f, 1.0f, 1.0f));
            break;

        case DummyItemType::Sphere:
            break;

        case DummyItemType::Icosahedron:
            model = GL_CHECK(DummyModel::MakeDummyModel<DummyItemType::Icosahedron>(attrib_type_list, with_rb, 2.0f));
            break;
    }

    model->SetScale(scale);
    model->SetRotation(rotation);
    model->SetTranslation(translation);

    AppendVertexAttribData(
            VertexAttribType::POSITION_F3,
            model->GetVertexData(VertexAttribType::POSITION_F3),
            model->GetVertexDataLength(VertexAttribType::POSITION_F3),
            0, 0);

    AppendVertexAttribData(
            VertexAttribType::NORMAL_F3,
            model->GetVertexData(VertexAttribType::NORMAL_F3),
            model->GetVertexDataLength(VertexAttribType::NORMAL_F3),
            0, 0);

    AppendVertexAttribData(
            VertexAttribType::UV1_F2,
            model->GetVertexData(VertexAttribType::UV1_F2),
            model->GetVertexDataLength(VertexAttribType::UV1_F2),
            0, 0);

    vertexNumber = model->GetVertexNumber();
    faceNumber = model->GetFaceNumber();
    SetElementData(model->GetIndexData(), model->GetIndexDataLength());
}